home *** CD-ROM | disk | FTP | other *** search
- /*
- * browser.c
- *
- * Forms Object class: BROWSER
- *
- * Written by: Mark Overmars
- *
- * Version 2.2 a
- * Date: Jan 25, 1993
- */
-
- #include <malloc.h>
- #include <string.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include "forms.h"
-
- #define NL 10
-
- /* Object specific information */
-
- typedef struct {
- int selected; /* Whether selected */
- char txt[FL_BROWSER_LINELENGTH]; /* The text */
- } LINE;
-
- typedef struct {
- LINE *text[FL_BROWSER_MAXLINE+1];/* The lines of text (line 0 is not used) */
- int topline; /* Current topline */
- int lines; /* Number of lines */
- int selectline; /* Last selected line */
- float fontsize; /* The character size */
- int fontstyle; /* Style of font */
- char specialkey; /* Key that indicates a special symbol */
- } SPEC;
-
-
- /***************** DATA STRUCTURE MAINTENANCE ************************/
-
- static void delete_line(FL_OBJECT *ob, int linenumb)
- /* Deletes a line from the browser */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- LINE *ttt;
- int i;
- ttt = sp->text[linenumb];
- for (i=linenumb; i<sp->lines; i++) sp->text[i] = sp->text[i+1];
- sp->text[sp->lines] = ttt;
- sp->lines--;
- if (sp->selectline == linenumb) sp->selectline = 0;
- else if (sp->selectline > linenumb) sp->selectline--;
- }
-
- static void insert_line(FL_OBJECT *ob, int linenumb, const char *newtext)
- /* Inserts a line of text to a browser */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- LINE *ttt;
- int i;
- if (sp->lines == FL_BROWSER_MAXLINE)
- {
- delete_line(ob,0);
- linenumb--;
- }
- sp->lines++;
- /* Create new line if required */
- if (sp->text[sp->lines] == NULL)
- sp->text[sp->lines] = (LINE *) fl_malloc(sizeof(LINE));
- /* Shift lines */
- ttt = sp->text[sp->lines];
- for (i=sp->lines-1; i>=linenumb; i--) sp->text[i+1] = sp->text[i];
- sp->text[linenumb] = ttt;
- /* Fill in line */
- sp->text[linenumb]->selected = 0;
- strncpy(sp->text[linenumb]->txt,newtext,FL_BROWSER_LINELENGTH);
- sp->text[linenumb]->txt[FL_BROWSER_LINELENGTH-1] = NULL;
- if (sp->selectline >= linenumb) sp->selectline++;
- }
-
- static void replace_line(FL_OBJECT *ob, int linenumb, const char *newtext)
- /* Replaces a line of text in a browser */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- /* Fill in line */
- strncpy(sp->text[linenumb]->txt,newtext,FL_BROWSER_LINELENGTH);
- sp->text[linenumb]->txt[FL_BROWSER_LINELENGTH-1] = NULL;
- }
-
- /******************************** DRAWING ********************************/
-
- static int partial = 0; /* Whether the next redraw should be partial.*/
- /* 0 = not, 1 = no back, 2 = no back, slider.*/
-
- static void calc_textarea(FL_OBJECT *ob, float *xx, float *yy,
- float *ww, float *hh, int *screenlines)
- /* Calculates the area in which the text is drawn */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- float charheight = fl_get_char_height(sp->fontsize, sp->fontstyle);
- /* character height */
- *xx = ob->x + 1.5*FL_BROWSER_BW;
- *yy = ob->y + 1.0*FL_BROWSER_BW;
- *ww = ob->w - 3.0*FL_BROWSER_BW;
- *hh = ob->h - 2.0*FL_BROWSER_BW;
- *screenlines = (int) (*hh / charheight);
- /* Check whether a slider will be shown */
- if (sp->lines > *screenlines)
- { *xx += 7.0*FL_BROWSER_BW; *ww -= 7.0*FL_BROWSER_BW;}
- }
-
- static void correct_topline(FL_OBJECT *ob)
- /* Corrects the position of the topline inside the browser */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- int screenlines; /* lines on screen */
- float xx,yy,ww,hh; /* text box */
- calc_textarea(ob,&xx,&yy,&ww,&hh,&screenlines);
- if (sp->lines > screenlines)
- {
- if (sp->lines - sp->topline + 1 < screenlines)
- sp->topline = sp->lines - screenlines + 1;
- if (sp->topline < 1) sp->topline = 1;
- }
- else
- sp->topline = 1;
- }
-
- static void draw_textline(FL_OBJECT *ob, int line, float xx, float yy, float ww,
- int back)
- /* Draws the line on the browser at postion xx,yy, with maximal width ww.
- back indicates whether the background should be drawn */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- char *str; /* Start of actual string */
- int style = sp->fontstyle; /* Actual font style used */
- float size = sp->fontsize; /* Actual font size used */
- int lcol = ob->lcol; /* Actual font color used */
- int align = FL_ALIGN_LEFT; /* Actual alignment used */
- float charheight = fl_get_char_height(size, style);
-
- /* Draw the selection box if required */
- if (line <= sp->lines && sp->text[line]->selected)
- fl_rect(xx,yy-0.6*charheight,ww,charheight,ob->col2);
- else if (back)
- fl_rect(xx,yy-0.6*charheight,ww,charheight,ob->col1);
- if (line > sp->lines) return;
-
- /* Check for special lines */
- str = sp->text[line]->txt;
- while (str[0] != '\0' && str[0] == sp->specialkey)
- {
- switch (str[1]) {
- case 'l': size = FL_LARGE_FONT;yy -= 5.0; break;
- case 's': size = FL_SMALL_FONT; break;
- case 'b': style = FL_BOLD_STYLE; break;
- case 'i': style = FL_ITALIC_STYLE; break;
- case 'f': style = FL_FIXED_STYLE; break;
- case 'c': align = FL_ALIGN_CENTER; break;
- case 'r': align = FL_ALIGN_RIGHT; break;
- case 'C':
- lcol = 0;
- while (str[2] >= '0' && str[2] <= '9')
- {lcol = 10* lcol + str[2] - '0'; str++;}
- break;
- case '_': /* line under it */
- fl_line(xx,yy-0.6*charheight,ww,1.0,BLACK);
- break;
- }
- str++; str++;
- }
- /* Draw the string */
- fl_drw_text_cursor(align,xx,yy,ww,0.0,lcol,size,style,str,0,-1);
- }
-
- static void draw_browslider(FL_OBJECT *ob, int screenlines)
- /* Draws the slider if required. */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- float slsize, slpos; /* slider size and position */
- slsize = (1.0*screenlines) / sp->lines;
- slpos = 1.0 - (1.0*sp->topline -1.0) / (sp->lines - screenlines);
- fl_drw_slider(ob->boxtype, ob->x,ob->y,7.0*FL_BROWSER_BW,ob->h,
- FL_BROWSER_SLCOL,FL_BROWSER_SLCOL,FL_VERT_SLIDER,
- slsize,slpos,"");
- }
-
- static void draw_browser(FL_OBJECT *ob)
- /* Draws the browser */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- float charheight = fl_get_char_height(sp->fontsize, sp->fontstyle);
- /* character height */
- int screenlines; /* lines on screen */
- int i; /* counters, etc. */
- float xx,yy,ww,hh; /* text box */
- calc_textarea(ob,&xx,&yy,&ww,&hh,&screenlines);
- correct_topline(ob);
- if (sp->lines > screenlines)
- {
- draw_browslider(ob,screenlines);
- fl_drw_box(ob->boxtype,ob->x+7.0*FL_BROWSER_BW,ob->y,
- ob->w-7.0*FL_BROWSER_BW,ob->h, ob->col1,FL_BROWSER_BW);
- }
- else
- {
- fl_drw_box(ob->boxtype,ob->x,ob->y,ob->w,ob->h,ob->col1,FL_BROWSER_BW);
- }
- fl_drw_text_beside(ob->align,ob->x,ob->y,ob->w,ob->h,
- ob->lcol,ob->lsize,ob->lstyle,ob->label);
- fl_set_clipping(xx,yy,ww,hh-1.0);
- for (i=screenlines-1; i >= 0 ; i--)
- draw_textline(ob,i+sp->topline,xx,yy+hh-(i+0.5)*charheight,ww,FALSE);
- fl_unset_clipping();
- }
-
- static void draw_browser_partial(FL_OBJECT *ob, int slid)
- /* Draws the contents of the browser only. slid indicated whether the
- slider should be redrawn. */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- float charheight; /* character height */
- int screenlines; /* lines on screen */
- int i; /* counters, etc. */
- float xx,yy,ww,hh; /* text box */
- charheight = fl_get_char_height(sp->fontsize, sp->fontstyle);
- calc_textarea(ob,&xx,&yy,&ww,&hh,&screenlines);
- correct_topline(ob);
- if (slid && sp->lines > screenlines) draw_browslider(ob,screenlines);
- fl_set_clipping(xx,yy,ww,hh-1.);
- for (i=screenlines-1; i >= 0 ; i--)
- draw_textline(ob,i+sp->topline,xx,yy+hh-(i+0.5)*charheight,ww,TRUE);
- fl_unset_clipping();
- }
-
- /***************** HANDLING EVENTS **************************/
-
- #define NOEVENT 0
- #define SELECTEVENT 1
- #define DESELECTEVENT 2
- #define SLIDEREVENT 3
- #define PAGEEVENT 4
-
- static int eventtype = NOEVENT; /* Type of interaction taking place */
- static int pagesize; /* Amount to scroll for page events */
-
- static int timdel; /* Time passes since last page change */
-
- static int handle_mouse(FL_OBJECT *ob, float mx, float my)
- /* handles a mouse change. returns whether a selection change has occured */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- float charheight = fl_get_char_height(sp->fontsize, sp->fontstyle);
- /* character height */
- int screenlines; /* lines on screen */
- float slsize,slpos,slval; /* slider size,pos and value */
- int line; /* new number of lines */
- int oldtopline = sp->topline; /* old value of topline */
- int newtopline; /* New topline */
- int slaction; /* Type of slider action */
-
- /* Check whether ther are any lines */
- if (sp->lines == 0) return FALSE;
-
- /* Compute possible slider position change */
- correct_topline(ob);
- screenlines = (int) ((ob->h - 2.0*FL_BROWSER_BW) / charheight);
- if (sp->lines > screenlines)
- {
- slsize = (1.0*screenlines) / sp->lines;
- slpos = 1.0 - (1.0*sp->topline -1.0) / (sp->lines - screenlines);
- slaction = fl_get_pos_in_slider(ob->x,ob->y,ob->w,ob->h,
- FL_VERT_SLIDER,slsize,mx,my, slpos,&slval);
- newtopline = (int) ((1.0-slval)*(sp->lines - screenlines) + 1.0);
- }
-
- /* Determine the type of event */
- if (eventtype == NOEVENT)
- {
- if (sp->lines > screenlines && mx < ob->x+7.0*FL_BROWSER_BW)
- {
- if (slaction == 0)
- eventtype = SLIDEREVENT;
- else
- {
- eventtype =PAGEEVENT;
- timdel = 0;
- if (slaction == -2) pagesize = screenlines;
- else if (slaction == -1) pagesize = 1;
- else if (slaction == 1) pagesize = -1;
- else if (slaction == 2) pagesize = -screenlines;
- }
- }
- else
- {
- eventtype = SELECTEVENT;
- line = sp->topline - (int) ((my-(ob->y+ob->h-FL_BROWSER_BW))/charheight);
- if (ob->type == FL_MULTI_BROWSER &&
- line >= 1 && line <= sp->lines && line < sp->topline+screenlines &&
- sp->text[line]->selected)
- eventtype = DESELECTEVENT;
- }
- }
-
- /* Handle the event */
- switch (eventtype) {
- case PAGEEVENT:
- if ((timdel++ % 30) == 0)
- {
- sp->topline += pagesize;
- correct_topline(ob);
- if (sp->topline == oldtopline) return 0;
- partial = 1; fl_redraw_object(ob);
- }
- return 0;
- case SLIDEREVENT:
- sp->topline = newtopline;
- correct_topline(ob);
- if (sp->topline == oldtopline) return 0;
- partial = 1; fl_redraw_object(ob);
- return 0;
- default:
- if (ob->type == FL_NORMAL_BROWSER) return 0;
- line = sp->topline - (int)((my-(ob->y+ob->h-FL_BROWSER_BW))/charheight);
- if (line<sp->topline) line = sp->topline;
- if (line>=sp->topline+screenlines) line = sp->topline+screenlines-1;
- if (line>sp->lines) line = sp->lines;
- if (eventtype == SELECTEVENT)
- {
- if (sp->text[line]->selected) return (ob->type != FL_MULTI_BROWSER);
- if (ob->type != FL_MULTI_BROWSER && sp->selectline > 0)
- sp->text[sp->selectline]->selected = 0;
- sp->text[line]->selected = 1;
- sp->selectline = line;
- }
- else /* eventtype == DESELECTEVENT && ob->type == FL_MULTI_BROWSER */
- {
- if (! sp->text[line]->selected) return 0;
- sp->text[line]->selected = 0;
- sp->selectline = -line;
- }
- partial = 2; fl_redraw_object(ob);
- return 1;
- }
- }
-
- /*-----------------------------------------------*/
-
- static int statuschanged = 0;
-
- static int handle_browser(FL_OBJECT *ob, int event, float mx, float my, char key)
- /* Handles the browser */
- {
- int i;
- SPEC *sp = ((SPEC *)(ob->spec));
- switch (event)
- {
- case FL_DRAW:
- if (partial == 0 || ob->form->doublebuf) draw_browser(ob);
- else if (partial == 1) draw_browser_partial(ob,TRUE);
- else if (partial == 2) draw_browser_partial(ob,FALSE);
- partial = 0;
- return 0;
- case FL_PUSH:
- eventtype = NOEVENT;
- statuschanged = 0;
- case FL_MOUSE:
- if (eventtype == SELECTEVENT || eventtype == DESELECTEVENT)
- {
- if (my < ob->y) fl_set_browser_topline(ob,sp->topline+1);
- else if (my > ob->y+ob->h) fl_set_browser_topline(ob,sp->topline-1);
- }
- if (handle_mouse(ob,mx,my)) statuschanged = 1;
- if (statuschanged && ob->type == FL_MULTI_BROWSER)
- { statuschanged = 0; return 1; }
- return 0;
- case FL_RELEASE:
- if (ob->type == FL_SELECT_BROWSER) fl_deselect_browser(ob);
- return statuschanged;
- case FL_FREEMEM:
- for (i=1; i<=FL_BROWSER_MAXLINE; i++)
- if (sp->text[i] != NULL) free(sp->text[i]);
- free(ob->spec);
- return 0;
- }
- return 0;
- }
-
- /*-----------------------------------------------*/
-
- FL_OBJECT *fl_create_browser(int type,float x,float y,float w,float h,
- const char *label)
- /* Creates a browser */
- {
- int i;
- FL_OBJECT *ob;
- SPEC *sp;
- ob = fl_make_object(FL_BROWSER,type,x,y,w,h,label,handle_browser);
- ob->boxtype = FL_BROWSER_BOXTYPE;
- ob->lcol = FL_BROWSER_LCOL;
- ob->align = FL_BROWSER_ALIGN;
- ob->col1 = FL_BROWSER_COL1;
- ob->col2 = FL_BROWSER_COL2;
-
- ob->spec = (int *) fl_malloc(sizeof(SPEC));
- sp = ((SPEC *)(ob->spec));
- sp->fontsize = FL_NORMAL_FONT;
- sp->fontstyle = FL_NORMAL_STYLE;
- sp->lines = 0;
- sp->topline = 1;
- sp->selectline = 0;
- sp->specialkey = '@';
- for (i=0; i <= FL_BROWSER_MAXLINE; i++) sp->text[i] = NULL;
-
- return ob;
- }
-
- FL_OBJECT *fl_add_browser(int type, float x, float y, float w, float h,
- const char *label)
- /* Adds an object */
- {
- FL_OBJECT *ob;
- ob = fl_create_browser(type,x,y,w,h,label);
- fl_add_object(fl_current_form,ob);
- return ob;
- }
-
- /*-----------------------------------------------*/
-
- void fl_set_browser_topline(FL_OBJECT *ob, int line)
- /* Sets the topline for the browser. */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- if (line<1) line = 1;
- if (line>sp->lines) line = sp->lines;
- if (line == sp->topline) return;
- sp->topline = line;
- fl_redraw_object(ob);
- }
-
- /*-----------------------------------------------*/
-
- void fl_clear_browser(FL_OBJECT *ob)
- /* Clears the browser. */
- {
- ((SPEC *)(ob->spec))->lines = 0;
- ((SPEC *)(ob->spec))->topline = 1;
- ((SPEC *)(ob->spec))->selectline = 0;
- fl_redraw_object(ob);
- }
-
- void fl_add_browser_line(FL_OBJECT *ob,const char *newtext)
- /* Adds a line of text to a browser */
- {
- insert_line(ob,((SPEC *)(ob->spec))->lines+1,newtext);
- fl_redraw_object(ob);
- }
-
- void fl_addto_browser(FL_OBJECT *ob, const char *newtext)
- /* Adds a line of text to a browser, and changes focus */
- {
- insert_line(ob,((SPEC *)(ob->spec))->lines+1,newtext);
- ((SPEC *)(ob->spec))->topline = ((SPEC *)(ob->spec))->lines;
- fl_redraw_object(ob);
- }
-
- void fl_insert_browser_line(FL_OBJECT *ob, int linenumb, const char *newtext)
- /* Inserts a line of text in a browser */
- {
- if (linenumb < 1 || linenumb > ((SPEC *)(ob->spec))->lines) return;
- insert_line(ob,linenumb,newtext);
- fl_redraw_object(ob);
- }
-
- void fl_delete_browser_line(FL_OBJECT *ob, int linenumb)
- /* Deletes a line from a browser. */
- {
- if (linenumb < 1 || linenumb > ((SPEC *)(ob->spec))->lines) return;
- delete_line(ob,linenumb);
- fl_redraw_object(ob);
- }
-
- void fl_replace_browser_line(FL_OBJECT *ob, int linenumb, const char *newtext)
- /* Replaces a line of text in a browser */
- {
- if (linenumb < 1 || linenumb > ((SPEC *)(ob->spec))->lines) return;
- replace_line(ob,linenumb,newtext);
- fl_redraw_object(ob);
- }
-
- const char *fl_get_browser_line(FL_OBJECT *ob, int linenumb)
- /* Returns a pointer to a particular line in the browser. */
- {
- if (linenumb < 1 || linenumb > ((SPEC *)(ob->spec))->lines) return NULL;
- return ((SPEC *)(ob->spec))->text[linenumb]->txt;
- }
-
- int fl_load_browser(FL_OBJECT *ob, char filename[])
- /* Sets the browser to a particular file */
- {
- SPEC *sp;
- FILE *fl;
- char newtext[FL_BROWSER_LINELENGTH];
- int c;
- int i;
- if (ob == NULL || ob->objclass != FL_BROWSER) return 0;
- sp = ((SPEC *)(ob->spec));
- fl_clear_browser(ob);
- if (filename == NULL || filename[0] == NULL)
- {fl_redraw_object(ob); return 1;}
- /* LOAD THE FILE */
- fl = fopen(filename,"r");
- if (fl == NULL) return 0;
- i = 0;
- do
- {
- c = getc(fl);
- if (c == NL || c == EOF)
- { newtext[i] = NULL; insert_line(ob,sp->lines+1,newtext); i = 0; }
- else if (c == 9) /* Tab */
- do
- if (i< FL_BROWSER_LINELENGTH-1) newtext[i++] = ' ';
- while ( i % 8 != 0 && i< FL_BROWSER_LINELENGTH-1);
- else if (i< FL_BROWSER_LINELENGTH-1)
- newtext[i++] = c;
- } while (c != EOF);
- fclose(fl);
- fl_redraw_object(ob);
- return 1;
- }
-
- int fl_get_browser_maxline(FL_OBJECT *ob)
- /* Returns the number of lines in the browser. */
- { return ((SPEC *)(ob->spec))->lines; }
-
- /*-----------------------------------------------*/
-
- void fl_select_browser_line(FL_OBJECT *ob, int line)
- /* Selects a line in the browser. */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- if (line < 1 || line > sp->lines) return;
- if (ob->type != FL_MULTI_BROWSER && sp->selectline >0)
- sp->text[sp->selectline]->selected = 0;
- sp->text[line]->selected = 1;
- sp->selectline = line;
- fl_redraw_object(ob);
- }
-
- void fl_deselect_browser_line(FL_OBJECT *ob, int line)
- /* Deselects a line in the browser. */
- {
- SPEC *sp = ((SPEC *)(ob->spec));
- if (line < 1 || line > sp->lines) return;
- sp->text[line]->selected = 0;
- if (ob->type != FL_MULTI_BROWSER && sp->selectline == line)
- sp->selectline = 0;
- else if (ob->type == FL_MULTI_BROWSER)
- sp->selectline = -line;
- fl_redraw_object(ob);
- }
-
- void fl_deselect_browser(FL_OBJECT *ob)
- /* Deselects all lines in the browser. */
- {
- int i;
- for (i=1; i<= ((SPEC *)(ob->spec))->lines; i++)
- ((SPEC *)(ob->spec))->text[i]->selected = 0;
- fl_redraw_object(ob);
- }
-
- int fl_isselected_browser_line(FL_OBJECT *ob, int line)
- /* Returns whether a line in the browser is selected. */
- {
- if (line < 1 || line > ((SPEC *)(ob->spec))->lines) return 0;
- return ((SPEC *)(ob->spec))->text[line]->selected;
- }
-
- int fl_get_browser(FL_OBJECT *ob)
- /* Returns the last selection in the browser. */
- { return ((SPEC *)(ob->spec))->selectline; }
-
- /*-----------------------------------------------*/
-
- void fl_set_browser_fontsize(FL_OBJECT *ob, float size)
- /* Sets the font size inside the browser. */
- {
- ((SPEC *)(ob->spec))->fontsize = size;
- fl_redraw_object(ob);
- }
- /*TCZ*/
- int fl_get_browser_topline(FL_OBJECT *ob)
- {
- return ((SPEC *)ob->spec)->topline;
- }
- void fl_set_browser_fontstyle(FL_OBJECT *ob, int style)
- /* Sets the font style inside the browser. */
- {
- ((SPEC *)(ob->spec))->fontstyle = style;
- fl_redraw_object(ob);
- }
-
- void fl_set_browser_specialkey(FL_OBJECT *ob, char specialkey)
- /* Sets the escape key used in the text */
- {
- ((SPEC *)(ob->spec))->specialkey = specialkey;
- fl_redraw_object(ob);
- }
-